﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RouterControl.IO;
using RouterControl.IO.Specification;
using System.Reflection;
using System.IO;

namespace RouterControlTest
{
	/// <summary>
	/// Summary description for DeviceDomSerialization
	/// </summary>
	[TestClass]
	public class DeviceDomDummy
	{
		public DeviceDomDummy()
		{
			//
			// TODO: Add constructor logic here
			//
		}

		private TestContext testContextInstance;

		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext
		{
			get
			{
				return testContextInstance;
			}
			set
			{
				testContextInstance = value;
			}
		}

		#region Additional test attributes
		//
		// You can use the following additional attributes as you write your tests:
		//
		// Use ClassInitialize to run code before running the first test in the class
		// [ClassInitialize()]
		// public static void MyClassInitialize(TestContext testContext) { }
		//
		// Use ClassCleanup to run code after all tests in a class have run
		// [ClassCleanup()]
		// public static void MyClassCleanup() { }
		//
		// Use TestInitialize to run code before running each test 
		// [TestInitialize()]
		// public void MyTestInitialize() { }
		//
		// Use TestCleanup to run code after each test has run
		// [TestCleanup()]
		// public void MyTestCleanup() { }
		//
		#endregion

		private static readonly string[] _types = new string[] { "string", "boolean", "ui4", "ui2", "i4", "i2" };
		private const int MaxDomDevices = 15;

		private readonly Random _rnd = new Random(DateTime.Now.Millisecond);
		private DeviceDom _dom;
		private int _domDevices = 0;

		private DeviceDom.Device CreateDevice()
		{
			var dd = new DeviceDom.Device();

			dd.DeviceName = Guid.NewGuid().ToString("N");
			dd.DeviceTypeId = "mytest:Device" + _rnd.Next() + ":1";
			dd.IsOptional = Convert.ToBoolean(_rnd.Next(0, 1));
			dd.IsRootDevice = false;

			// add services
			{
				var ci = _rnd.Next(3, 9);

				for (int i = 0; i < ci; i++)
					dd.Services.Add(CreateService());
			}

			// add children
			{
				var cc = _rnd.Next(0, 10);

				for (int j = _rnd.Next(0, 5); (j < cc) && (++_domDevices < MaxDomDevices); j++)
					dd.ChildDevices.Add(CreateDevice());
			}

			return dd;
		}

		private DeviceDom.Service CreateService()
		{
			var ss = new DeviceDom.Service();

			ss.ServiceName = ("Service" + _rnd.Next());
			ss.ServiceTypeId = ("mytest:Service" + _rnd.Next() + ":" + _rnd.Next(1, 5));

			// add variables
			{
				var ci = _rnd.Next(3, 9);

				for (int i = 0; i < ci; i++)
					ss.StateVariables.Add(CreateStateVariable());
			}

			// add actions
			{
				var ci = _rnd.Next(3, 9);

				for (int i = 0; i < ci; i++)
					ss.Actions.Add(CreateAction(ss.StateVariables));
			}

			return ss;
		}

		private DeviceDom.Action CreateAction(IList<DeviceDom.StateVariable> vars)
		{
			if (vars == null)
				throw new ArgumentNullException("vars");

			var r = new DeviceDom.Action();

			r.ActionName = ("Action" + _rnd.Next());

			var cp = _rnd.Next(0, 5);

			for (int i = 0; i < cp; i++)
			{
				var p = new DeviceDom.ActionArgument();

				p.ArgumentName = ("Param" + i);
				p.Direction = (Convert.ToBoolean(_rnd.Next(0, 1)) ? DeviceDom.ActionParameterDirection.In : DeviceDom.ActionParameterDirection.Out);
				p.RelatedVariable = vars[_rnd.Next(1, vars.Count) - 1];

				r.Arguments.Add(p);
			}

			return r;
		}

		public DeviceDom.StateVariable CreateStateVariable()
		{
			var r = new DeviceDom.StateVariable();

			r.VariableName = ("Variable" + _rnd.Next());
			r.IsOptional = Convert.ToBoolean(_rnd.Next(0, 1));
			r.SendEventsAttribute = Convert.ToBoolean(_rnd.Next(0, 1));
			r.DataTypeName = _types[_rnd.Next(1, _types.Length) - 1];

			// allowed values?
			if (r.DataTypeName.Equals("string", StringComparison.InvariantCultureIgnoreCase) &&
				!Convert.ToBoolean(_rnd.Next(0, 2)))
			{
				var aw = new List<string>();
				var swc = _rnd.Next(1, 15);

				for (int h = 0; h < swc; h++)
					aw.Add("TestVal " + h);

				r.AllowedValues = aw.ToArray();
			}

			return r;
		}

		[TestInitialize]
		public void BuildDom()
		{
			_domDevices = 0;

			var d = new DeviceDom();

			d.RootDevice = CreateDevice();
			d.RootDevice.IsRootDevice = true;
			d.SchemaId = DeviceHelpers.CreateId(d.RootDevice.DeviceTypeId, d.RootDevice.DeviceName);

			_dom = d;
		}

		[TestMethod]
		public void SerializeDom()
		{
			var dom = _dom.ToXml();

			Console.WriteLine(dom);

			var newDom = DeviceDom.CreateFromXml(dom);

			// check
			Assert.AreEqual(dom, newDom.ToXml(), "(de-)serialization inconsistent");
		}

		[TestMethod]
		public void GenerateServices()
		{
			var services = _dom.GetAllServices();

			// generate interfaces
			var g = new DeviceServiceCompiler(new ServiceInterfaceCompilerVariation());

			g.AddServicesAll(services);

			Console.WriteLine(g.GetCsharpCode());

			// generate implementation
			var g2 = new DeviceServiceCompiler(new ServiceImplementationCompilerVariation());

			g2.AddServicesAll(services);

			Console.WriteLine(g2.GetCsharpCode());
		}

		[TestMethod]
		public void GenerateServiceInterfaces()
		{
			var g = new DeviceServiceCompiler(new ServiceInterfaceCompilerVariation());

			var services = _dom.GetAllServices();

			g.AddServicesAll(services);

			Console.WriteLine(g.GetCsharpCode());
		}
	}
}
